/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#ifndef _SERIALIZE_H
#define _SERIALIZE_H

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <limits>
#include <sstream>

#include "lexical.h"
#include "syntax.h"
#include "gType.h"

#define NEW_LINE "\r\n"

//! Nástroj pro serializaci.
/*!
 * Uloží do souboru kontejner, objekt nebo gType v reprezentaci g-kódu.
 * Ke sve činosti potřebuje i původní nezměněný vstupní soubor, protože
 * struktura, jako je kontejner, obsahuje jen kód mezi tagy 
 * (#OBJECT name)...(#!OBJECT name) a informaci o jejich umístění v původním
 * zrojovém souboru. Z těchto informací je poté sestavem nový soubor, obsahující
 * starý obsah mimo obsahu umístěného mezi tagy.
*/
class serialize{

	private:
		//! Zaokrouhlování floutů.
		static const unsigned FLOAT_PRECISION = 5;
		//! Vnitřní buffer.
		static const long TRANSFER_BUFFER = 1024;
		
		//! Výstupní soubor.
		std::ostream *outputFile;
		//! Vstupní původní soubor.
		std::istream *inputFile;
		//! Původní maska výstupního souboru.
		std::ios_base::iostate exceptionsOutputBitmask;
		//! Původní maska vstupního souboru.
		std::ios_base::iostate exceptionsInputBitmask;
		//! Buffer souřadnic.
		float xyzCoordinates[3];
		
		bool flag;
		
		//! Inicializace souřadnic.
		void initCoordinates();
		//! Zápis souřadnic do streamu.
		/*!
		* Zapíše souřadnice do streamu v úsporné podobě. To znamená, že
		* souřadnice, které jsou stejné z předchozího kroku nebudou uvedeny.
		* Zvýší se tak čitelnost kódu.
		*/
		void getCoordinates(std::ostringstream &, gTypeGo &, bool = false);
		//! Zápis souřadnic do streamu.
		/*!
		* Zapíše souřadnice do streamu v úsporné podobě. To znamená, že
		* souřadnice, které jsou stejné z předchozího kroku nebudou uvedeny.
		* Zvýší se tak čitelnost kódu. Souřadníce středu jsou zapsány
		* za pomocí parametrů I a J. Na souřadnice středu usporná forma
		* být aplikovaná nemůže už z principu.
		*/
		void getCoordinates(std::ostringstream &, gTypeGoCircle &);
		//! Přesune blok dat ze vstupního souboru do výstupního.
		/*!
		* Používá se při serializaci objektů nebo kontejnerů, kdy je
		* nutné zapsat i data, které nejsou obsažena v objektech.
		* Využívá bufferu o velikosti TRANSFER_BUFFER.
		*/
		void transfer(long, long)
			throw(std::ofstream::failure, std::ifstream::failure);
		//! Vrací offset konce vstupního souboru.
		unsigned long getEndOffset() const 
			throw(std::ifstream::failure);
		
        void writeFeedSpindle(std::ostringstream &, float, int, gObject &);
		
	public:
		//! Konstruktor serializace.
		/*!
		 * Vstupní a výstupní soubor nesmí být totožný, pokud je třeba 
		 * zapisovat do totožného souboru je třeba použít např dočasný soubor.
		 * Vstupní a výstupní stream musí být otevřen v binárním módu.
		* \param ofile Výstupní soubor.
		* \param ifile Původní vstupní soubor.
		*/
		serialize(std::ostream *, std::istream *);
		//! Destruktor serializace.
		~serialize();
		
		//! Nastaví zapisování nových offsetu do kontejneru.
		/*!
		 * Standartně je nastaveno na true.
		*/
		void setOffsets(bool);
		bool getOffsets() const;
		
		//! Zapíše kontejner do výstupního souboru.
		/*!
		 * S pojmem zápisu kontejneru je spojeno i výhledání částí zrojového
		 * textu, který není obsažen v kontejneru, tedy v objektech kontejneru
		 * ,ale v původním vstupním souboru. V objektech kontejneru jsou uvedeny
		 * jen informace, kde se přesně se v souboru nachází. Vyhazuje vyjímku
		 * spojenou se čtením případě zapisem do souboru.
		* \param container Kontejner, který chceme serializovat.
		*/
		void writeGContainer(gObjectContainer &) throw(std::ofstream::failure);
		//! Zapíše objekt do výstupního souboru.
		/*!
		 * S pojmem zápisu objektu je spojeno i výhledání částí zrojového
		 * textu, který není obsažen v objektu 
		 * ale v původním vstupním souboru. V objektech kontejneru jsou uvedeny
		 * jen informace, kde přesně se v souboru nachází. Vyhazuje vyjímku
		 * spojenou se čtením případě zapisem do souboru.
		* \param object Objekt, který chceme serializovat.
		*/
		void writeGObject(gObject &) throw(std::ofstream::failure);
		//! Zapíše gType do výstupního souboru.
		/*!
		 * Pouze převede repzentaci gTypu ma textovou reprezenaci, jakou známe
		 * z g-kódu a zapíše do výstupního souboru.
		* \param type G-typ, který chceme serializovat.
		*/
		void writeGType(gType &, bool = false) throw(std::ofstream::failure);

};

#endif
